package com.ztesoft.web.common;

import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.sql.Types;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Pattern;

import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.JSchException;
import com.ztesoft.framework.log.ZTEsoftLogManager;
import com.ztesoft.framework.util.Utils;
import com.ztesoft.web.common.customdb.SQLHelper;
import com.ztesoft.web.common.vo.HostInfoPOJO;
import com.ztesoft.web.ssh.PublicSSHExec;
import com.ztesoft.web.ssh.SSH2Client;
import com.ztesoft.web.ssh.SSHClient;


/**
 * 
 * 与业务耦合较强的工具类<br>
 * 
 * @author <a href="mailto:lin.weibin@zte.com.cn">lin.wb</a> 2016年5月20日 上午10:31:17
 * @version 1.0
 */
public final class Util {
	private static final ZTEsoftLogManager logger = ZTEsoftLogManager
			.getLogger(Util.class);
	private Util(){}
	
	/**
	 * 拼接DB_URL
	 * 
	 * @param dbType
	 *            数据库类型
	 * @param ip
	 *            主机IP
	 * @param port
	 *            端口
	 * @param dbName
	 *            数据库名
	 * @param dbLinkName
	 *            实例名
	 * @param dbLinkParam
	 *            实例参数
	 * @return 链接
	 */
	public static String bldConnURL(String dbType, String ip, String port, String dbName, String dbLinkName,
			String dbLinkParam) {
		// jdbc:oracle:thin:@10.45.44.212:1521:ora11g
		// jdbc:mysql://10.45.44.186:3306/scmdb
		// jdbc:informix-sqli://10.45.44.201:7088/prod_new:informixserver=infoserver;
		StringBuilder sb = new StringBuilder();
		if (DMSConstant.ORACLE.equals(dbType)) {
			sb.append("jdbc:oracle:thin:@").append(ip).append(":").append(port).append(":").append(dbLinkName);
		} else if (DMSConstant.INFORMIX.equals(dbType)) {
			sb.append("jdbc:informix-sqli://").append(ip).append(":").append(port).append("/").append(dbLinkName)
					.append(":informixserver=").append(dbName);
			if (Utils.notEmpty(dbLinkParam)) {				
				sb.append(";").append(dbLinkParam);
			} else {
				sb.append(";").append("DB_LOCALE=en_us.819;CLIENT_LOCALE=en_us.57372;NEWCODESET=GBK,8859-1,819;IFX_USE_STRENC=true");
			}
		} else if (DMSConstant.MYSQL.equals(dbType)) {
			sb.append("jdbc:mysql://").append(ip).append(":").append(port).append("/").append(dbLinkName);
			if (Utils.notEmpty(dbLinkParam))
				sb.append("?").append(dbLinkParam);
		}
		return sb.toString();
	}
	
	/**
	 * 统一字段类型，不同数据库对应的字段类型可能不一样
	 * 
	 * @param type int
	 * @return ~
	 */
	public static int uniteColumnType(int type) {
		// java.sql.Types.BIGINT:-5
		// java.sql.Types.INTEGER:4
		// java.sql.Types.DECIMAL:3
		// java.sql.Types.NUMERIC:2
		// 都是数字类型
		if (java.sql.Types.BIGINT == type || java.sql.Types.INTEGER == type 
				|| java.sql.Types.DECIMAL == type || java.sql.Types.NUMERIC == type ) {
			return java.sql.Types.NUMERIC;
		}
		// java.sql.Types.DATE:91
		// java.sql.Types.TIME:92
		// java.sql.Types.TIMESTAMP:93
		// 都是时间类型
		else if (SQLHelper.isDate(type)) {
			return Types.DATE;
		} else {
			return type;
		}
	}

	public static String getCPUCMD(String osType) {
		if (DMSConstant.OS_TYPE_AIX.equals(osType)) {
			return DMSConstant.OS_TYPE_AIX_CPU;
		} else if (DMSConstant.OS_TYPE_LINUX.equals(osType)) {
			return DMSConstant.OS_TYPE_LINUX_CPU;
		} else if (DMSConstant.OS_TYPE_HP_UX.equals(osType)) {
			return DMSConstant.OS_TYPE_HP_UX_CPU;
		}
		return null;
	}

	public static String getUsedMEMCMD(String osType) {
		if (DMSConstant.OS_TYPE_AIX.equals(osType)) {
			return DMSConstant.OS_TYPE_AIX_MEM_USED;
		} else if (DMSConstant.OS_TYPE_LINUX.equals(osType)) {
			return DMSConstant.OS_TYPE_LINUX_MEM_USED;
		} else if (DMSConstant.OS_TYPE_HP_UX.equals(osType)) {
			return DMSConstant.OS_TYPE_HP_UX_MEM_USED;
		}
		return null;
	}
	

	public static String getMEMCMD(String osType) {
		if (DMSConstant.OS_TYPE_AIX.equals(osType)) {
			return DMSConstant.OS_TYPE_AIX_MEM_TOTAL;
		} else if (DMSConstant.OS_TYPE_LINUX.equals(osType)) {
			return DMSConstant.OS_TYPE_LINUX_MEM_FREE;
		} else if (DMSConstant.OS_TYPE_HP_UX.equals(osType)) {
			return DMSConstant.OS_TYPE_HP_UX_MEM_TOTAL;
		}
		return null;
	}
	
	/**
	 * 获取监测执行命令
	 * @param osType 主机类型
	 * @param checkCmdType
	 * 		获取CPU执行命令	0 DMSConstant.CHECK_CMD_CPU;<br>
	 * 		获取used-mem执行命令	1 DMSConstant.CHECK_CMD_USED_MEM;<br>
	 * 		监测内存命令	2 DMSConstant.CHECK_CMD_MEM;<br>
	 * 		获取informix锁模式执行命令<i>informix特有</i>	3 DMSConstant.CHECK_CMD_IFX_LMODE; -- <b>作废，直接获取</b><br>
	 * ...待完善添加<br>
	 * @return ~
	 */
	public static String getExecCmd(String osType, int checkCmdType) {
		String execCmd = null;
		switch (checkCmdType) {
		case DMSConstant.CHECK_CMD_CPU:
			execCmd = getCPUCMD(osType);
			break;
		case DMSConstant.CHECK_CMD_USED_MEM:
			execCmd = getUsedMEMCMD(osType);
			break;
		case DMSConstant.CHECK_CMD_MEM:
			execCmd = getMEMCMD(osType);
			break;
//		case DMSConstant.CHECK_CMD_IFX_LMODE:
//			execCmd = DMSConstant.IFX_LMODE_CMD;
//			break;
		default:
			break;
		}
		return execCmd;
	}
	
	/**
	 * map to str key0=value0&key1=value1
	 * @param paramMap
	 * @return ~
	 */
	public static String bldMap2Str(Map<String, String> paramMap) {
		StringBuilder sb = new StringBuilder();
		if (!paramMap.isEmpty()) {
			for (Entry<String, String> paramEntry : paramMap.entrySet()) {
				if (sb.length() < 1) {
					sb.append(paramEntry.getKey()).append("=").append(paramEntry.getValue());
				} else {
					sb.append("&").append(paramEntry.getKey()).append("=").append(paramEntry.getValue());
				}
			}
		}
		return sb.toString();
	}

	/**
	 * 单条数据长度、记录数 除1024 保留指定小数位
	 * @param oneRecordSize 单条长度
	 * @param totalCount 记录数
	 * @param scale 精度
	 * @return ~
	 */
	public static BigDecimal divValue2BigDecimal(int oneRecordSize, int totalCount, int scale) {
		return BigDecimal.valueOf(((double)oneRecordSize*totalCount)/1024).setScale(scale, RoundingMode.HALF_UP);
	}
	
	/**
	 * 根据数据库类型返回查询剩余表空间的SQL语句/ 单位GB
	 * 
	 * @param dbType
	 *            数据库类型
	 * @param tableName
	 *            表名
	 * @return 查询剩余表空间的SQL语句
	 */
	public static String getSQLByDBType(String dbType, String tableName, String dbName) {
		String sql = "";
		if (DMSConstant.DB_LINK_CATEGORY_ORACLE.equals(dbType.toUpperCase())
				|| DMSConstant.DB_LINK_CATEGORY_TT.equals(dbType.toUpperCase())) {
			sql = " SELECT total.tablespace_name, round(free.GB,5), round(total.GB,5) "
					+ " FROM (SELECT tablespace_name, SUM(bytes) / 1024 / 1024 / 1024 as GB FROM dba_free_space "
					+ " GROUP BY tablespace_name) free, (SELECT tablespace_name, SUM(bytes) / 1024 / 1024 / 1024 AS GB "
					+ " FROM dba_data_files GROUP BY tablespace_name) total WHERE free.tablespace_name = total.tablespace_name "
					+ " AND free.tablespace_name in (SELECT TABLESPACE_NAME FROM USER_TABLES WHERE TABLE_NAME='"
					+ tableName.toUpperCase() + "' ) ";

		} else if (DMSConstant.DB_LINK_CATEGORY_MYSQL.equals(dbType.toUpperCase())) {
			sql = " SELECT TABLE_SCHEMA, ROUND(SUM(DATA_LENGTH+INDEX_LENGTH)/ 1024 / 1024 / 1024,5),ROUND(SUM( DATA_LENGTH+INDEX_LENGTH +DATA_FREE)/ 1024 / 1024 / 1024,5) "
					+ " FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA='"+dbName+"'";

		} else if (DMSConstant.DB_LINK_CATEGORY_INFORMIX.equals(dbType.toUpperCase())) {
			sql = " select d.name,sum(round(nfree/1024/1024,5)) , sum(round(chksize/1024/1024,5))  from sysmaster:sysdbspaces d, "
					+ " sysmaster:syschunks c where d.dbsnum = c.dbsnum and d.name in ( select sd.name "
					+ " from sysmaster:systabnames st, sysmaster:sysdbspaces sd where sd.dbsnum = trunc(st.partnum/(1024*1024)) "
					+ " and st.tabname='"+tableName+"' )group by d.name";
		}
		return sql;
	}

	/**
	 * 任务状态为 1 、2 、4时为数据恢复的执行 <br>
	 * 1、 2、 4含义由数据恢复开发补充,常量类定义含义 TODO 
	 * @param state
	 * @return ~
	 */
	public static boolean isRecovery(Integer state) {
		return ((int) state==1 || (int) state==2 || (int) state ==4);
	}

	/**
	 * 按计划判断手工任务
	 * @param execType 2
	 * @return
	 */
	public static boolean isHanderTask(String execType) {
		return DMSConstant.EXEC_TYPE_HAND.equals(execType);
	}
	
	/**按计划判断系统自动任务
	 * @param execType 1
	 * @return
	 */
	public static boolean isAutoTask(String execType) {
		return DMSConstant.EXEC_TYPE_AUTO.equals(execType);
	}
	
	/**
	 * 按任务优先级判断手工任务
	 * @param priority 1
	 * @return
	 */
	public static boolean isHanderTask(Integer priority) {
		
		return 1 == (int) priority;
	}
	
	/**按任务优先级判断系统自动任务
	 * @param priority 2
	 * @return
	 */
	public static boolean isAutoTask(Integer priority) {
		return 2 == (int) priority;
	}

	   /**
     * 对执行系统命令结果处理
     * @param commandResult
     * @return
     */
	public static String dealResult(String commandResult) {
		String[] commandResultArr = null;
		if(commandResult.contains("\r\n")){
			commandResultArr= commandResult.split("\r\n");
		}else if(commandResult.contains("$")){
			commandResultArr= commandResult.split("$");
		}else if(commandResult.contains("#")){
			commandResultArr= commandResult.split("#");
		}
		if (!Utils.isEmpty(commandResultArr)) {
			if (commandResultArr.length == 3) {
				commandResult = commandResultArr[1];
			}else if(commandResultArr.length==2){
				if(commandResultArr[0].contains("$")){
					commandResult = commandResultArr[0].split("\\$")[1];
				}else{
					commandResult = commandResultArr[0];
				}
			}else if(commandResultArr.length==4){
				if (Pattern.compile("[.0-9]*").matcher(commandResultArr[1]).matches()) {							
					commandResult = commandResultArr[1];
				} else {							
					commandResult = commandResultArr[2];
				}
			}
		}
		return commandResult;
	}
	
	public static String dealResultT(String commandResult) {
		String[] commandResultArr = null;
		if(commandResult.contains("\r\n")){
			commandResultArr= commandResult.split("\r\n");
		}
		List<String> resultList = new ArrayList<String>();
		for (int i = 0, j = commandResultArr.length; i < j; i++) {
			String value = commandResultArr[i];
			System.err.println(value);
			if (i ==0) {
				value = rmPromp(value);
			}
			if (i == j -1) {
				value = rmPromp(value);
			}
			
			resultList.add(value);
		}

		return Utils.convertIdList2StringByComma(resultList);
	}

	private static String rmPromp(String value) {
		String[] result = null;
		if (value.contains("find ")) {
			return null;
		}
		if(value.contains("$")){
			result = value.split("\\$");
		} else  if(value.contains("#")){
			result = value.split("\\#");
		}else{
			return  value;
		}
		return result.length ==2 ? result[1] : null;
	}
	
	/**
	 * SSH方式执行脚本命令
	 * @param hostInfoPOJO
	 * @param command
	 * @return
	 */
	public static List<String> execShellBySSH( HostInfoPOJO hostInfoPOJO, String ... command) {
		List<String> resultList = new ArrayList<String>();
		String execResult = null;
		SSHClient client = null;
		ChannelExec channel ;
		try {
			client = new SSHClient(hostInfoPOJO.getUserName(), hostInfoPOJO.getPwd(), hostInfoPOJO.getHostIp(), hostInfoPOJO.getPort());
			client.creatSession();
			PublicSSHExec SSHExec = new PublicSSHExec();
			for (String shell : command) {
				channel = (ChannelExec) client.getExecChannel();
				execResult = SSHExec.execNormalCommand(channel, shell);
				System.err.println(execResult);
				resultList.add(execResult);
			}
		} catch (JSchException e) {
			//TODO
			System.out.println("SSH客户端远程连接异常或者执行命令异常" + e);
		} catch (Exception e) {
			//TODO
			System.out.println("读取命令执行信息异常" + e);
		} finally {
			client.closeConnect();
		}
		return resultList;
	}
	
	public static List<Object> execShellBySSHMethod(HostInfoPOJO hostInfoPOJO, String... command) {
		SSH2Client ssh = new SSH2Client(hostInfoPOJO);
		List<Object> resultList = new ArrayList<Object>();
		String execResult = null;
        try {
			boolean login = ssh.ssh2Login();
			if(login){
				logger.info("服务端主机登录成功");
				for (int i = 0; i < command.length; i++) {
					String shell = command[i];
					if (i != 0 && i % 10 == 0) {
						Thread.sleep(100);
					}
					Map<String, String> execMap = new HashMap<String, String>();
					logger.info("执行命令{0}",shell);
					Map<String, Object> map = ssh.execNormalCommand(login, shell);
					String status = map.get("status").toString();
					if("0".equals(status)){
						logger.info("[success] "+shell+" 命令执行成功");
						if(map.get("outStr") != null){
							logger.info("[INFO] outStr=\n" + map.get("outStr").toString());
						}
						if(map.get("outErr") != null){
							logger.info("[INFO] outErr=\n" + map.get("outErr").toString());
						}else{
							logger.info("[INFO] the message is empty!");
						}
					}else if("1".equals(status)){
						logger.info("[fail] "+shell+" 命令执行失败");
						if(map.get("outStr") != null){
							logger.info("[INFO] outStr=\n" + map.get("outStr").toString());
						}else if(map.get("outErr") != null){
							logger.info("[INFO] outErr=\n" + map.get("outErr").toString());
						}else{
							logger.info("[INFO] the message is empty!");
						}
					}else{
						logger.info("[fail] "+shell+" 命令执行失败");
					}
					if(map.get("outErr") != null){
						execResult =  map.get("outErr").toString();
						execMap.put("ERR", execResult);
					}else if(map.get("outStr") != null){
						execResult = map.get("outStr").toString();
						execMap.put("SUC", execResult);
					}
					//
					resultList.add(execMap);
				}
			}else{
				logger.info("服务端主机登录失败");
			}
		} catch (IOException e) {
			logger.error("[error] ssh login fail,ip:"+hostInfoPOJO.getHostIp()+",user:"+hostInfoPOJO.getUserName()+",password:"+hostInfoPOJO.getPwd()+",error info:"+e,e);
		}catch(Exception e){
			logger.error("[error] ssh exception,ip:"+hostInfoPOJO.getHostIp()+",user:"+hostInfoPOJO.getUserName()+",password:"+hostInfoPOJO.getPwd()+",error info:"+e,e);
		}finally{
			ssh.closeConnect();
		}
        return resultList;
	}
}

